package com.cctc.juc.source.Bitc.Glock;
/**
 * 【JUC 显式锁】
 * 1. 简述：JUC 显式锁是基于 AQS 线程同步队列（基类）实现的线程同步工具。
 * 与 Java 内置锁不同，JUC 显式锁使用纯 Java 语言实现（基于用户态下的 CAS “自旋” 机制），在竞争激烈的情况下，避免了 Java 内置锁（重量级锁）需要 CPU 频繁在用户态和内核态之间来回切换所带来的性能开销问题；此外 Java 内置锁功能相对单一，不具备一些高级锁功能，例如非阻塞抢锁、限时抢锁、可中断抢锁等，以及支持维护多个条件队列，以提高锁的使用效率等；JUC 显式锁就是为了解决 Java 内置锁（重量级锁）的性能和功能问题而生的，由于其加锁和解锁方法都是通过 Java API 显式进行的，所以被称为显式锁。可以这样说，Java 内置锁可以做的事情，JUC 显式锁都能做到，而 JUC 显式锁能做到的事情，Java 内置锁却做不到。
 * 2. 锁的分类：
 * - 依据同步资源的访问方式以及对应锁的实现方式，分为写锁->悲观（加）锁->独占锁、读锁->悲观（加）锁->乐观（无，版本控制）锁->共享锁。
 * - 依据锁的排队过程，分为阻塞式抢锁、非阻塞式抢锁、限时阻塞式抢锁、不可中断式抢锁、可中断式抢锁；
 * - 依据锁的分配方式，分为公平锁、非公平锁、可重入锁、不可重入锁；
 * - 依据同步资源的协作方式，分为信号量、倒数闩、循环屏障、移相器等；
 * - 依据锁的组合方式，分为读写锁、印戳锁、分段锁。
 * - 依据锁的协作方式，分为联合锁、红锁；
 * - 依据锁的应用场景，分为本地锁、分布式锁。
 * 3. JUC 显式锁顶层接口及其核心方法：
 * 1）Lock 接口，相比于 synchronized 同步方法和同步代码块提供了更具扩展性的锁操作，例如声明了一些高级锁特性，支持非阻塞抢锁、限时阻塞抢锁、可中断抢锁，以及允许维护多个条件队列，以提高锁的使用效率。
 * ReentrantLock 是该接口的一个标准实现类。
 * - void lock()，对标于 Java 内置锁，不可中断式阻塞抢锁。
 * - boolean tryLock()，非阻塞抢锁。
 * - boolean tryLock(long time, TimeUnit unit) throws InterruptedException，限时抢锁。
 * - void lockInterruptibly() throws InterruptedException，可中断抢锁。
 * - void unlock()，对标于 Java 内置锁，释放锁。
 * - Condition newCondition()，对标于 Java 内置锁的 WaitSet，获取一个与 Lock 锁绑定条件队列，允许维护多个条件队列，以提高锁的使用效率。
 * 2）ReadWriteLock 接口，ReadWriteLock 读写锁是 JDK 5 新增的一个接口，基于 AQS 独占锁、共享锁模板流程定义了获取读（共享）锁和写（互斥）锁的方法，是一种用来提升程序并发性能的锁分离（组合）技术。
 * 一个 ReadWriteLock 维护了一对关联的读写锁，一个（共享，在没有写线程的情况下，一个读锁可以同时被多个读线程持有）用于只读操作，一个（独占）用于写操作。
 * ReentrantReadWriteLock 是该接口的一个标准实现类，它最多支持分别创建 65535 个读锁和写锁。
 * - Lock readLock()，基于 AQS 共享锁模板流程，获取读（共享）锁；
 * - Lock writeLock()，基于 AQS 独占锁模板流程，获取写（互斥）锁。
 * 4. JUC 显式锁体系结构：
 * 1）独占锁：ReentrantLock [核心]（独占、可重入、公平 & 非公平）；
 * - ReentrantLock 是 JUC 显式锁的一个基础实现类，作为 [独占 | 共享锁]、[可重入锁]、[非公平锁 | 公平锁] 的一个标准实现类，实现了 Lock 接口，除了拥有与 Java 内置锁相同的并发性和内存语义之外，还具备一些高级锁特性，例如非阻塞抢锁、限时阻塞抢锁、可中断抢锁，以及支持维护多个同步队列，以提高锁的使用效率等；此外，由于 ReentrantLock 内部依赖于一个基于 AQS 基类实现的 Sync 同步器实例实现（独占、可重入）锁的抢占与释放逻辑，同时支持公平和非公平两种抢锁模式，因此在竞争激烈的情况下，可以表现出比 Java 内置（重量级）锁更佳的性能。
 * 2）共享锁：ReadLock（读锁）、Semaphore（信号量）、CountDownLatch（倒数闩 / 闭锁）、CyclicBarrier（循环屏障）、Phaser（移相器）；
 * 3）组合锁：ReentrantReadWriteLock（读写锁）、StampedLock（印戳锁，乐观 [无锁，版本控制] 读 & 悲观 [加锁] 写）、基于 LongAdder、ConcurrentHashMap 思想实现的 “热点分散型” 分段锁。
 * - ReentrantReadWriteLock 是 [组合锁] 的一个标准实现类，实现了 ReadWriteLock 接口，作为 [读写锁] 的一个标准实现类，内部分别基于 AQS 的独占锁、共享锁模板流程实现了共享（读）锁和独占（写）锁的抢占与释放逻辑，与单一的 ReentrantLock 独占锁相比，组合起来的（悲观）读读（共享）锁、写写 | 写读（独占）锁可以极大程度提升读操作的并发效率，非常适用于 “读多写少” 的场景。
 * - StampedLock 是 ReentrantReadWriteLock 的一种改进，读读不加锁，读写加写锁，写后读再加读锁，真正实现了读读共享乐观（无锁，版本控制）锁、写写 | 写读悲观（加锁）独占锁，将读操作的并发效率发挥到了极致，极其适用于 “读多写少” 的场景。
 * 6. 总结：
 * Java 内置锁（偏向锁、轻量级锁），以及 JUC 显式锁都是基于 CAS “自旋” 操作实现的乐观锁。
 * 因此，在竞争不激烈的情况下，二者性能差不多；但是在竞争激烈的情况下，Java 内置锁会膨胀为重量级锁，该锁是基于 Linux 内核中提供的 Mutex Lock 互斥锁实现的，会造成 CPU 在用户态和核心态之间频繁切换，开销太大；而 JUC 显式锁基于 AQS 基类进行实现，AQS 其实就是将 “内核态” 的 [重量级锁] 在 Java 应用层面基于 CAS “自旋” 机制显式实现了一遍，并通过优秀的设计（RUNNABLE -> WAITING -> RUNNABLE -> ...）完美地解决了在竞争激烈的场景下 CAS “空自旋” 线程所来带的 CPU 性能损耗问题，有效避免了 Java 内置锁（重量级锁）需要 CPU 频繁在用户态和内核态之间来回切换所带来的性能开销问题。此外 JUC 显式锁还具备一些高级锁功能，例如非阻塞抢锁、限时抢锁、可中断抢锁等，以及支持维护多个条件队列，以提高锁的使用效率等。
 * 总而言之，JUC 显式锁就是为了解决 Java 内置锁的性能和功能问题而生的，由于其加锁和解锁方法都是通过 Java API 显式进行的，所以被称为显式锁。
 * 可以这样说，Java 内置锁可以做的事情，JUC 显式锁都能做到，而 JUC 显式锁能做到的事情，Java 内置锁却做不到。
 * 补充：锁的优化策略。
 * - 组合锁（读写分离）、分段锁、设置过期时间自动释放锁、多个线程尽量以相同的顺序获取资源等。
 * 提示：锁粒度越细，冲突越小，并发越高，同时会导致加锁慢、效率低，且容易产生死锁。
 * 因此，不能刻意将锁的粒度过于细化，不然可能会出现线程加锁和解锁次数过多，反而效率不如加一把粗粒度的锁。
 * 7. 面试题：
 * 1）什么是死锁？如何避免死锁？
 * 死锁指的是两个或两个以上的线程在执行过程因争抢（锁）资源而造成的一种相互等待的现象。
 * 若无外力作用，它们将陷入僵局，均无法继续向下执行。
 * 死锁的发生必须满足四个必要条件：独占、不可剥夺、请求与保持、循环等待。
 * 避免死锁发生的方法：破坏死锁产生的四个必要条件。
 * 例如：
 * - 将系统中所有的（锁）资源设置标志位并排序，规定所有申请（锁）资源的线程必须按照一定的顺序（升序或降序）进行操作，从而阻止循环等待条件，避免死锁；
 * - 非阻塞抢锁、限时阻塞抢锁、可中断抢锁，以及给锁加一个过期时间，到期自动释放锁等，破坏请求与保持、不可剥夺、循环等待等条件，避免死锁，例如如果使用的是 JUC 显式锁的 lockInterruptibly() 方法可中断抢锁，就可以在检测到死锁发生后，使用 Thread.interrupt() 方法去中断死锁线程，不让死锁线程一直等待下去。
 * 死锁检测方法：
 * - 如果使用的是 synchronized 内置锁，当死锁发生时，JVM 会在生成线程方法堆栈转储快照时输出锁定信息，标识死锁或其他异常行为的来源。
 * - 如果使用的是 JUC 显式锁，则可以使用 ManagementFactory 获取 ThreadMXBean 线程管理实例，然后通过以下方法输出死锁或其他异常行为的来源。
 * - ManagementFactory.getThreadMXBean.findDeadlockedThreads()，检测由于抢占 Java 内置锁，JUC 显式锁所引起死锁的线程。
 * - ManagementFactory.getThreadMXBean.findMonitorDeadlockedThreads()，仅检测由于抢占 Java 内置锁所引起死锁的线程。
 */